﻿using MengLin.OOP.DesignPattern.Flyweight.Implements;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MengLin.OOP.DesignPattern.Flyweight.Letter
{
    /// <summary>
    /// 统一入口
    /// </summary>
    public class FlyweightLetterFactory
    {
        /// <summary>
        /// 静态字典缓存，准备个容器，对象复用
        /// </summary>
        private static Dictionary<WordType, BaseWord> _flyweightFactoryDictionary = new Dictionary<WordType, BaseWord>();
        private readonly static object FlyweightFactoryLock = new object();
        /// <summary>
        /// 1.5个线程同时执行，字典为空，所以会同时构造5次字母M
        /// 2.最后只打印了一个MENGLIN，因为其他线程挂掉了，因为字典添加时异常了
        /// 3.2个L属于小概率事件，前2个线程是同时添加E，所以都没失败，所以L有两个，
        ///    但是到了L，又冲突了
        /// 4.异常我怎么没看到？子线程的异常是获取不到的，没有抛到主线程，除非WaitAll
        /// </summary>
        /// <param name="wordType"></param>
        /// <returns></returns>
        public static BaseWord CreateWord(WordType wordType)
        {
            if (!_flyweightFactoryDictionary.ContainsKey(wordType))
                //是为了优化性能，避免对象已经被初始化后，再次请求还需要等待锁
            {
                lock (FlyweightFactoryLock)//Monitor.Enter,保证方法体只有一个线程可以进入
                {
                    if (!_flyweightFactoryDictionary.ContainsKey(wordType))
                    {
                        BaseWord word = null;
                        switch (wordType)
                        {
                            case WordType.M:
                                word = new M();
                                break;
                            case WordType.E:
                                word = new E();
                                break;
                            case WordType.N:
                                word = new N();
                                break;
                            case WordType.G:
                                word = new G();
                                break;
                            case WordType.L:
                                word = new L();
                                break;
                            case WordType.I:
                                word = new I();
                                break;
                            default:
                                throw new Exception("wrong wordtype!");
                        }
                        _flyweightFactoryDictionary.Add(wordType, word);
                    }
                }
            }
            return _flyweightFactoryDictionary[wordType];
        }
    }

    public enum WordType
    {
        M,
        E,
        N,
        G,
        L,
        I
    }
}
